//
//  MetalView.swift
//  videoPlayer
//
//  Created by xwl on 2019/2/26.
//  Copyright © 2019年 xuwanliang. All rights reserved.
//

import MetalKit
import UIKit
import Foundation


class MetalView: MTKView {
    fileprivate weak var _metalLayer:CAMetalLayer! = nil
    var commandQueue: MTLCommandQueue?
    
    //清除屏幕颜色
    private var _cleanColor: MTLClearColor = MTLClearColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
    
    private var render3d: Render3D! = nil
    private var renderrgb: RenderRGB! = nil
    private var renderOLED25: OLED25! = nil
    
    var rps: MTLRenderPipelineState?
    var vertexBuffer: MTLBuffer?
    var colorSamplerState: MTLSamplerState!
    
    var rgbTexture: MTLTexture?
    //var rgbTexture2: MTLTexture?
    
    var y_Texture: MTLTexture?
    var uv_Texture: MTLTexture?
    
    fileprivate var _textureCache: CVMetalTextureCache? = nil
    
    var screenWidth: Int = 0
    var screenHeight: Int = 0
    var picList: [String] = [
                    "timg",
                    "maliao"]
    var currPicID:Int = 0
    var printOnce:Bool = true
    
    required init(coder:NSCoder){
        super.init(coder:coder)
        
        initCommon()
    }
    
    override func layoutSubviews() {
            super.layoutSubviews()
            self.autoResizeDrawable = false
            self.drawableSize = CGSize(width: 2868, height: 1320)
        }
    
    func initCommon(){
        
        //if true, 不会自动调用draw进行刷新，只有在主线程调用setNeedsDisplay()后，才会执行draw
        //self.enableSetNeedsDisplay = true
        //for compute shader
        self.framebufferOnly = false
        self.autoResizeDrawable = false
        self.drawableSize = CGSize.init(width: 2868, height: 1320)
        _metalLayer = self.layer as? CAMetalLayer
        
        device = MTLCreateSystemDefaultDevice()
        commandQueue = device?.makeCommandQueue()
        CVMetalTextureCacheCreate(nil, nil, device!, nil, &_textureCache)
        
        ScreenSize()
        loadPic()
        
        render3d = Render3D(device: device!, commandQueue: commandQueue!, width: screenWidth, height: screenHeight)
        renderrgb = RenderRGB(device: device!, commandQueue: commandQueue!, width: screenWidth, height: screenHeight)
        renderOLED25 = OLED25(device: device!, commandQueue: commandQueue!, width: screenWidth, height: screenHeight)
        
        let outTexture = currentDrawable?.texture
        //print("drawable size %d x %d", outTexture?.width as Any, outTexture?.height as Any)
        
        
    }
    
    func ScreenSize(){
        let drawableSize = UIScreen.main.bounds.size
        print("UI Size", drawableSize)
        screenWidth = Int(drawableSize.width * UIScreen.main.nativeScale)
        screenHeight = Int(drawableSize.height * UIScreen.main.nativeScale)
        if screenHeight > screenWidth{
            let tmp = screenHeight
            screenHeight = screenWidth
            screenWidth = tmp
        }
        print("screen size: \(screenWidth) x \(screenHeight)")
    }
    
    
    func loadPic(){
        if let path = Bundle.main.path(forResource: picList[currPicID], ofType: "jpg"){
            let textureLoader = MTKTextureLoader(device: device!)
            do{
                try rgbTexture = textureLoader.newTexture(URL: URL(fileURLWithPath: path), options: nil)
            }catch let error{
                fatalError("\(error)")
            }
        }
    }
    
    override func draw(_ rect: CGRect) {
        //print("draw....")
        
        if printOnce {
            printOnce = false
            let outTexture = currentDrawable?.texture
            print("draw drawable size %d x %d", outTexture?.width as Any, outTexture?.height as Any)
        }
            
        
        
        if let texture = renderrgb._rgbTexture{
            render3d.render(drawable: currentDrawable, rpd: currentRenderPassDescriptor, texture: texture)
            renderOLED25.render(drawable: currentDrawable, rpd: currentRenderPassDescriptor, texture: texture)
        }
    }
    
    public func drawYUV(_ pixelBuffer: CVPixelBuffer!){

        if let tc = _textureCache{
            var y_texture: CVMetalTexture? = nil
            let y_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0)
            let y_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0)
            CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, tc, pixelBuffer, nil, MTLPixelFormat.r8Unorm, y_width, y_height, 0, &y_texture)
            
            var uv_texture: CVMetalTexture? = nil
            let uv_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1)
            let uv_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1)
            CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, tc, pixelBuffer, nil, MTLPixelFormat.rg8Unorm, uv_width, uv_height, 1, &uv_texture)
            
            self.y_Texture = CVMetalTextureGetTexture(y_texture!)!
            self.uv_Texture = CVMetalTextureGetTexture(uv_texture!)!
            
            if let ytext = y_Texture,
                let uvtext = uv_Texture{
                renderrgb.render(drawable: currentDrawable!, rpd: currentRenderPassDescriptor!, texture: ytext, textureuv: uvtext)
            }
            //print("y_Texture size \(String(describing: y_Texture?.width)) x \(String(describing: y_Texture?.height))")
            //print("y_Texture size \(String(describing: uv_Texture?.width)) x \(String(describing: uv_Texture?.height))")
            
        }
    }
    
    
    public func updateColor(){
        _cleanColor.red -= 0.1
        if _cleanColor.red <= 0.1{
            _cleanColor.red = 1.0
        }
        currPicID += 1
        currPicID = currPicID%2
        loadPic()
    }
//    func setDrawableSize(){
//        self.contentScaleFactor = UIScreen.main.nativeScale
//        _metalLayer = self.layer as? CAMetalLayer
//        self._metalLayer.contentsScale = self.contentScaleFactor
//        print("drawableSize0: \(_metalLayer.drawableSize)")
//    }
}
